<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

    <script>
        // var foo = {
        //     value: 1
        // };

        // function bar() {
        //     console.log(this.value)
        // }

        // var bindFoo =  bar.bind(foo)
        // bindFoo()

        // Function.prototype.bind2 = function (context) {
        //     var self = this;
        //     console.log(this)
        //     return function () {
        //         return self.apply(context)
        //     }
        // }

        // var foo = {
        //     value: 1
        // };

        // function bar() {
        //     console.log(this.value)
        // }

        // var bindFoo = bar.bind(foo)
        // bindFoo()
        // var foo = {         
        //     value: 1
        // };

        // function bar(name, age) {
        //     console.log(this.value)
        //     console.log(name)
        //     console.log(age)
        // }

        // var fooBind = bar.bind(foo, 'daisy');
        // fooBind(18)
        // // 1
        // // daisy
        // // 18
        // let a = {
        //     length:2,
        //     0:'zero',
        //     1: 'first'
        // }
        // console.log(Array.prototype.slice.call(a))
        // console.log(Array.prototype.slice.call(a,1))
        // Function.prototype.bind2 = function (context) {
        //     var self = this;
        //     // 获取 bind2 函数从第二个参数到最后一个参数
        //     var args = Array.prototype.slice.call(arguments, 1)

        //     return function () {
        //         // 这个时候的 arguments 是指bind返回的函数传入的参数
        //         var bindArgs = Array.prototype.slice.call(arguments)

        //         return self.apply(context, args.concat(bindArgs))
        //     }
        // }

        // var foo = {
        //     value: 1
        // }
        // function bar(name, age) {
        //     console.log(this.value)
        //     return {
        //         value: this.value,
        //         name: name,
        //         age: age
        //     }
        // }
        // var bindFoo = bar.bind2(foo, 'daisy')
        // console.log(bindFoo(18))
        // var value = 2;

        // var foo = {
        //     value: 1
        // };

        // function bar(name, age) {
        //     this.hobit = 'shopping'
        //     console.log(this.value)
        //     console.log(name)
        //     console.log(age)
        // }

        // bar.prototype.friend = 'kevin'

        // var barFoo = bar.bind(foo, 'daisy')
        // var obj = new barFoo(18)
        // // undefined
        // // daisy
        // // 18
        // console.log(obj.hobit)
        // console.log(obj.friend)
        // // shopping
        // // kevin

        Function.prototype.bind2 = function (context) {
            if (typeof this !== 'function') {
                throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
            }

            var self = this;

            var args = Array.prototype.slice.call(arguments, 1);

            var fNOP = function () { };

            var fBound = function () {
                var bindArgs = Array.prototype.slice.call(arguments);
                return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs))
            }

            fNOP.prototype = this.prototype
            fBound.prototype = new fNOP()
            return fBound;
        }
        var foo = {
            value: 1
        }
        function bar(name, age) {
            console.log(this.value)
            console.log(name, age)
        }
        var f = bar.bind2(foo, 'daisy', 18)
        f()
    </script>
</body>

</html>